<!DOCTYPE html>
<html lang="zh-CN">

<head>
	<meta charset="UTF-8" />
	<title>hsp尚硅谷</title>
	<link rel="stylesheet" href="../style/css/article.css">
	<!-- <script src="js/a.js"></script> -->
</head>

<body>
<a id="top" href="#"></a>
<div id="particles-js"></div>
</div>
<div class="text">
<h1>Text</h1>
<ul>
<li>下划线在Go中是个特殊的标识符,称为空标识符,可以代表任何其他的标识符,但是它对应的值会被忽略,所以仅能作为占位符,不能作为标识符</li>
<li>25个关键字不能用,int竟然都不是关键字,可以用作标识符,哈哈,真是为了简洁啥也不要了</li>
<li>包名,保持包的名字和目录尽量保持一致,尽量采用简短有意义的包名,不要和标准库冲突</li>
<li>驼峰法命名,变量名和函数名,我比较喜欢小驼峰,</li>
<li>Java用public,protected等来控制访问范围</li>
<li>Go语言如果变量名,函数名,常量名首字母大写,则可以被其他的包访问,如果首字母小写,则只能在本包中使用,大写public,小写private,unexported</li>
<li>这么nb,果然简洁,怪不得我用fmt.Println时这个大驼峰弄得我这么难受呢,原来是故意的</li>
<li>自己引用自己的包,工作目录/src不用写,从src向下写路径,这就是配置GOPATH的目的</li>
<li>各种运算符应该没啥区别吧</li>
<li>关注一下取整和取模的规则,其他的没啥区别</li>
<li>两个整数整除,去掉小数</li>
<li>var f1 float32 = 10 / 4 这个竟然不报错,我还以为没有显示类型转换会报错呢,这个结果是2</li>
<li>有浮点数参与运算,则是除法</li>
<li>取模的本质是 a % b = a - (a / b) * b, 所以符号和a相同</li>
<li>Golang的自增和自减只能当作一个独立语句使用,不能像其他语言那样又i++,又++i,Go只有i++,i--</li>
<li>Golang的设计者去掉C/Java中的自增自减容易混淆的写法,让Golang简洁统一</li>
<ul>
<li>关系运算符/比较运算符</li>
</ul>
<li>结果是bool类型的,用作contition,要么真要么假,关系运算符组成的表达式,我们称为关系表达式,比较运算符==和赋值运算符=别写错了</li>
<ul>
<li>逻辑运算符</li>
<li> 赋值运算符</li>
</ul>
<li>将表达式运算后的值赋给指定的变量,有各种复合赋值运算符,左移后赋值,右移后赋值,按位与或异或后赋值</li>
<li>赋值运算符左侧是变量,右侧是变量,常量,或者表达式</li>
<li>Go语言没有三元运算符,被拿掉了,哈哈,用if吧</li>
<li>运算符优先级, + 高于 移位</li>
<li>位运算符</li>
<li>只要区分好Go语言的逻辑移位和算术移位即可</li>
<li>左移<<符号位不变,低位补0</li>
<li>右移>>低位溢出,符号位不变,用符号位补溢出的高位,这是算术右移</li>
<li>没有三元运算符,Golang的设计理念,一个问题只有一个解决方案</li>
<li>键盘输入语句</li>
<li>fmt.Scanln, fmt.Scanf, 一个按行读入,一个按format读入,类似C的scanf,传入变量的地址,和Java体系不同</li>
<li>进制</li>
<li>Golang和C一样不能用二进制表示一个整数常量,%b是输出二进制的格式,16进制0x或0X</li>
</ul>
<pre>
// AddUpper()是一个函数,返回的类型是func (int) int
// 返回了一个匿名函数,但是这个匿名函数引用到了外面的n
// 所以这个匿名函数就和n形成了一个整体,构成了闭包
// 理解:闭包像一个类,函数是操作,这个n是字段
// 当我们反复调用f函数时,n只初始化一次,所以有累加的效果
// 我们要搞清楚闭包的关键,就是要分析出返回的函数和它引用的变量
func AddUpper() func (int) int {
    var n int = 10
    return func (x int) int {
        n = n + x
        return n
    }
}
func main() {
    f := AddUpper()
    fmt.Println(f(1))//11
    fmt.Println(f(2))//13
    fmt.Println(f(3))//16
// 累加器里的n是不重复被初始化的
}
</pre>
<pre>
// 写一个函数,传入一个后缀,例如.jpg,返回一个闭包,这个闭包能识别这个后缀
// 这个闭包传入一个文件名,如果有后缀,返回,如果没有该后缀,加上
package main
import (
    "fmt"
    "strings"
)
func makeSuffix(suffix string) func (string) string {
    mySuf := suffix    // 这里是没必要的,用形参位置的那个suffix就行
// 我是把闭包和类的成员变量这种联系起来了,其实这个量在形参位置也无妨
    return func (inName string) string {
        if (strings.HasSuffix(inName, mySuf)) { // 这里我习惯if后加括号了,改一下
            return inName
        } else {
            return inName + mySuf
        }
    }
}
func main() {
    f := makeSuffix(".jpg")
    res := f("abc.jpg")
    fmt.Println(res)
    res2 := f("def")
    fmt.Println(res2)
}
</pre>
<ul>
<li>defer</li>
</ul>
<div class="h2i1">
<h2>字符串常用的系统函数</h2>
</div><div class="h2i2">
<h2>日期和时间</h2>
</div><div class="h2i3">
<h2>内置函数</h2>
</div><ul>
<li>四种初始化数组的方式</li>
</ul>
<pre>
var intArr [5]int = [...]int {10, 20, 30, 40, 50}
ss := intArr[1:3] // ss引用到这个元素的下标1(include),到下标3(exclude),
// len是目前有多少个元素,cap是容量,可以存放多少个,切片的容量是可以动态变化的
切片在内存中的形式 引用的起始地址,len,cap
所以slice其实相当于一个结构体
type slice struct {
    prt *[2]int
    len int
    cap int
}
slice是数组的引用,无论改哪一边,另一边是同步的,因为是同一块内存
我现在的问题在于,增加元素怎么办???
通过make来创建切片
var 切片名 []int = make([]int, 4, [cap]), cap可选,不可小于len
通过make方式创建的切片对应的数组是由make底层维护的,对外不可见
定义一个切片,直接就指定具体数组,使用原理类似make的方式
var ss []string = []string {"tom", "jack", "marry"}
所以一共讲了三种创建切片的方式
方式1引用一个已有的数组,方式2通过make,方式3直接指定一个数组
1和2的区别,1是直接引用数组,这个数组是事先存在的,程序员可见的
2是通过make来创建切片,make也会创建一个数组,是由切片在底层维护,程序员是不可见的
细节
切片初始化引用数组的时候,是一个半闭半开区间,当从0开始或者到len结束时可以省略不写这项
切片仍然不能越界,要在[0, len)内使用,但是可以动态增长
cap是一个内置函数,用于统计切片的容量,
切片定义完还不能使用,因为本身是一个空的,需要make后或者引用数组后才能使用
可以对切片再次进行切片,都是指向同一内存空间的,一个变全都变
ss = append(ss, 1, 2, 3), 这回懂了为什么动态追加不会影响原来的数组了,因为没有改ss,而是生成一个新的切片
ss = append(ss, ss2...), 切片append一个新的切片,这三个点是固定的写法
大概因为Go没有函数重载吧
append底层是数组扩容,先创建一个更大的,然后进行数值拷贝,再返回一个新的切片
之前我不理解的是有一个数组a,s是它的切片,比如说是s := a[0:1],如果我往s后面append,那a不就被改变了么,现在知道了,append会创建一个新的切片,然后返回,我们是让s指向这个新的切片,和a没什么关系了,那还有个问题,这个cap有什么用啊,又不是预先分配好的空间,有啥用?
切片的拷贝, copy(dst, src), 两个都是切片类型,把一个大的copy小的也没问题,后面的就不拷贝嘛
切片是引用传递,做参数传递传的是地址
string和slice
string的底层是byte数组,因此string可以进行切片操作
string和切片在内存中是这样的,底层是byte数组,string和切片维护一个地址和长度
string其实就是一个切片呀,
string是不可变的,不能用str[0] = 'a'来修改,
如果需要修改字符串,先将string -> []byte 或 []rune -> 修改 -> 再重写成string,转换通过强制类型转换就能转,中文的时候用[]rune
## 排序和查找
二维数组
var arr [4][6]int, 首先一个大小为4的数组,数组中存储的是[6]int类型,所以是4行6列
二维数组的内存布局,和C一样,在内存中连续存储
可以先声明,后赋值,也可以声明的时候直接初始化
var arr [2][3]int = [2][3]int{1,2,3
# map
var 变量名 map[keytype]valuetype
什么不可以做key? slice, map, function, 因为这几个不能用 == 来判断
map可以做value,也就是可以多重map
声明map不分配内存,需要make后才能赋值和使用
先声明,再make,再赋值,ok
声明的同时直接make,在赋值,ok
声明的时候直接给初值,ok,底层还是make, 
myMap := map[string]string{"abc": "def", "zzz": "xxx", }map的这么赋值最后一个也要写逗号
map的增删改查,遍历,长度
增和改直接通过下标来实现
插入已经存在的key相当于修改替换
delete内置函数进行删除传入map和key,这个key不存在就不操作也不会报错
Golang没有删除map所有元素的那种clear函数,一个一个删,没必要,可以make一个新的,原来的成为垃圾,被gc回收
查询 value, res = myMap["key"], 如果res为true,就已存在,且会同时返回value是多少
map的遍历,用for-range, for k, v := range mapName {
用len函数查看map中有几对元素
map切片
切片的数据类型如果是map,则我们称为slice of map,这样使用则map的个数就可以动态变化了
比如我们想维护多个map,可以用一个大的map套这些map,但是这样得给每个小的一个key才能存在大map中,如果用slice of map就方便了,有个大容器[]map[string]string,里面存放任意个map
注意切片要make,每个map也要make,切片的动态增加需要append方法
map排序
Golang中的map是无序的,既不按照key排序,又不按照添加顺序排序,每次遍历得到的输出可能也不一样
Golang中没有一个专门的方法针对map的key进行排序
Golang中的map排序是先将key进行排序,然后根据key值遍历输出即可,先将map的key放到切片中,对切片排序,然后按照这个顺序来输出map的值, sort.Ints([] int)
细节
map是引用类型,遵守引用类型传递的机制
map的容量达到限制的时候会自动扩容,不需要像slice一样调用append方法扩容
map的value经常使用struct,更适合管理复杂的数据
	</div>
<script src="../style/js/particles.min.js"></script>
<script src="../style/js/particles.config.js"></script>
</body>
</html>
